package StratelegoGame;

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

import SwingLib.Message;
import TwoClientGameConnection.TCGGeneralLib;

/**
 * This class runs the entire stratelego go. It displays in game chat
 * and the game board. It also communicates with the game logic.
 * @author Jace Ferguson
 * @filename BoardGame.java
 *
 */
public class BoardGame extends JFrame implements GameBoard2DApplicationProtocol, ActionListener{
	private JLabel inGameChatLabel;	
	private JTextArea chatHistoryTextArea;
	private JTextField statusTextField;
	private JTextField chatText;
	private JButton sendButton;
	private JButton startGameButton;
	private JButton changeUserName;
	private JButton changeHostParametersButton;
	private JButton retryConnectionButton;
	private ServerProtocol serverProtocol;
	private ClientProtocol clientProtocol;
	//Won't really need these until another board format was implemented
//	private GameBoard board;
//	private GameBoardPieceHoard hoard;
	private GameBoard2DLogic logic;
	private String user = "";
	private String connectHost = "";
	private String serverHost;
	private Integer gamePort = 4900;
	private boolean startServer = true;
	private JPanel boardPanel;
	private JPanel hoardPanel;

	/**
	 * Construct the board game object.
	 */
	public BoardGame()
	{
		setTitle("Stratelego");
		this.logic = GameBoard2DLogic.getInstance();
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		//Server must use the computers host name. 
		this.serverHost = TCGGeneralLib.getHostIPAddress();
		JPanel panel = GetGamePanel();
		this.setConnectionParameters();
		this.add(panel);
		this.pack();
		this.setLocationRelativeTo(null);
		this.setVisible(true);
	}

	/**
	 * Action handlers for the buttons in the application.
	 */
	public void actionPerformed(ActionEvent e)
	{
		Object source = e.getSource();
		if (source == sendButton && this.clientProtocol != null)
		{
			if(this.clientProtocol != null)
			{
				this.clientProtocol.sendChatMessage(chatText.getText());
				this.chatText.setText("");
			}	 			
		}
		else if(source == this.startGameButton)
		{
			if(this.logic != null)
			{
				if(this.logic.getPlayersConnected())
					this.logic.pieceSetupFinished();
				else
				{
					new Message("The other player hasn't connected yet. Try starting later.");
				}
			}
		}
		else if(source == this.changeHostParametersButton)
		{
			this.getHostFromUser();
		}
		else if(source == this.changeUserName)
		{
			this.requestUsername();
			if(this.clientProtocol != null)
				this.clientProtocol.sendChangeAlias(this.user);
			else
				new Message("Client not available. Try reconnecting.", "Client Not Found", Message.WARNING);				
		}
		else if(source == this.retryConnectionButton)
		{
			int result = JOptionPane.showConfirmDialog(this, "You are going to restart the connection, are you sure you want to do it?");
			if(result == JOptionPane.YES_OPTION)
			{
				if(this.startServer == true)
				{
					result = JOptionPane.showConfirmDialog(this, "You are running a game server. Do you want to reset the server also?");
					if(result == JOptionPane.YES_OPTION)
					{
						this.startServer();
					}
					this.connectClient(); //Try to connect another client.
				}
			}
		}
	}

	/**
	 * Add a chat message to the chat display area.
	 * @param	message	String	new message to add.
	 */
	public void addMessageToDisplay(String message)
	{
		this.chatHistoryTextArea.append(message + "\n");
	}

	/**
	 * Connect the client protocol to the server.
	 */
	public void connectClient()
	{
		if(this.clientProtocol != null) //Gracefully kill any current client.
			this.clientProtocol.sendQuitClient();

		this.clientProtocol = null;

		if(this.connectHost != null && this.connectHost.length() > 0)
		{
			this.clientProtocol = new ClientProtocol(this.connectHost, this.gamePort);
			this.clientProtocol.setApplicationHandler(this); //Set the client to use this window for application handleing
			this.clientProtocol.setGameLogic(this.logic);	//Set the game logic for the protocol
			this.clientProtocol.connectToServer();	//Actually connect to the server.
			this.logic.setClientProtocol(this.clientProtocol);
		}
		else //No host, get if first, then try to reconnect.
		{
			this.getHostFromUser();
			this.connectClient();
		}
	}

	/**
	 * Set up the main window panel.
	 * @return	JPanel
	 */
	public JPanel GetGamePanel()
	{
		JPanel panel = new JPanel();
		panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));

		//Game board panel
		JPanel gameBoardPanel = new JPanel();
		gameBoardPanel.setLayout(new BoxLayout(gameBoardPanel, BoxLayout.Y_AXIS));

		gameBoardPanel.add(this.setupButton());
		gameBoardPanel.add(Box.createRigidArea(new Dimension(0, 10)));
		gameBoardPanel.add(this.boardPanel = new JPanel());
		gameBoardPanel.add(Box.createRigidArea(new Dimension(0, 10)));
		gameBoardPanel.add(this.hoardPanel = new JPanel());
		panel.add(gameBoardPanel); //Add the game board to window
		//Add space between components
		panel.add(Box.createRigidArea(new Dimension(0, 15)));
		//Add the chat component
		panel.add(this.setupChat());
		panel.add(Box.createRigidArea(new Dimension(0, 10)));

		statusTextField = new JTextField();
		statusTextField.setEditable(false);
		statusTextField.setFocusable(false);

		//Add status bar
		panel.add(statusTextField);		

		return panel;

	}

	/**
	 * Request a connection host from the user.
	 */
	public void getHostFromUser()
	{
		this.connectHost = JOptionPane.showInputDialog(this, "Enter host:", "Get Host", JOptionPane.PLAIN_MESSAGE);
	}

	/**
	 * Start the game so the player can place their board.
	 */
	public void initializeGame()
	{
		if(this.clientProtocol != null)
		{
			this.clientProtocol.sendReadyToStartNewGame();
		}	 
		else
		{
			new Message("Client not available. Try reconnecting.", "Client Not Found", Message.WARNING);
		}
	}

	/**
	 * Get a user name from the user. Used as the client's alias.
	 */
	public void requestUsername()
	{
		this.user = JOptionPane.showInputDialog("Enter a user name:");
	}

	/**
	 * Add a board object to the window. 
	 * Could potentially be 3D
	 * @param board	GameBoard object
	 */
	public void setBoard(GameBoard board)
	{
		assert(board != null);
		//this.board = board;
		this.logic.setBoard(board);
		this.boardPanel.removeAll();
		//More decoupling needed here if 3D was implemented
		this.boardPanel.add((GameBoard2D)board);
		this.pack();
	}

	/**
	 * Request whether or not to create the server.
	 */
	public void setConnectionParameters()
	{
		int useServer = JOptionPane.showConfirmDialog(this, "Do you want to create a server.");
		if(useServer == 0)
		{
			this.connectHost = this.serverHost;
		}
		else
		{
			this.startServer = false;
			this.getHostFromUser();
		}
	}

	/**
	 * Add the hoard object to the window.
	 * @param hoard
	 */
	public void setPieceHoard(GameBoardPieceHoard hoard)
	{
		assert(hoard != null);
		//this.hoard = hoard;
		this.logic.setHoard(hoard);
		this.hoardPanel.removeAll();
		//More decoupling needed here if 3D was implemented
		this.hoardPanel.add((GameBoard2DPieceHoard)hoard);
		pack();
	}

	/**
	 * Setup and add the buttons
	 * @return	JPanel filled with buttons
	 */
	public JPanel setupButton()
	{
		JPanel buttonPane = new JPanel();
		buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.X_AXIS));
		this.startGameButton = new JButton("Start Game");
		this.startGameButton.addActionListener(this);
		buttonPane.add(this.startGameButton);
		this.changeHostParametersButton = new JButton("Change Host");
		this.changeHostParametersButton.addActionListener(this);
		buttonPane.add(this.changeHostParametersButton);
		this.changeUserName = new JButton("Change User Name");
		this.changeUserName.addActionListener(this);
		buttonPane.add(this.changeUserName);
		this.retryConnectionButton = new JButton("Reconnect");
		this.retryConnectionButton.addActionListener(this);
		buttonPane.add(this.retryConnectionButton);
		return buttonPane;	 			 		
	}

	/**
	 * Setup the chat area and return in a panel
	 * @return
	 */
	public JPanel setupChat()
	{
		JPanel chatPanel = new JPanel();
		chatPanel.setLayout(new BoxLayout(chatPanel, BoxLayout.Y_AXIS));
		inGameChatLabel = LabelFactory.createLabel("In Game Chat:");
		chatPanel.add(inGameChatLabel);

		chatHistoryTextArea = new JTextArea(5,20);
		chatHistoryTextArea.setLineWrap(true);
		chatHistoryTextArea.setWrapStyleWord(true);
		chatHistoryTextArea.setEditable(false);
		JScrollPane chatHistoryScroll = ScrollPaneFactory.createPane(chatHistoryTextArea);
		chatPanel.add(chatHistoryScroll);

		chatPanel.add(Box.createRigidArea(new Dimension(0, 4)));
		chatText = new JTextField();
		chatText.setEditable(true);
		chatText.setFocusable(true);
		chatPanel.add(chatText);
		chatPanel.add(Box.createRigidArea(new Dimension(0, 2)));
		sendButton = ButtonFactory.createButton("Send", this);
		chatPanel.add(sendButton);
		return chatPanel;
	}

	/**
	 * Start the initial game connection state.
	 * Server starts first if user so chooses to create the server.
	 */
	public void setupConnection()
	{
		if(this.startServer)
		{
			this.startServer();
		}
		this.connectClient();
		try
		{
			Thread.sleep(1000);
		}
		catch(InterruptedException e){}
	}

	/**
	 * Start the game server.
	 */
	public void startServer()
	{
		if(this.serverProtocol != null) //Gracefully kill a currently running server
		{
			this.serverProtocol.killServer();
		}
		this.serverProtocol = null;
		this.serverProtocol = new ServerProtocol();
		this.serverProtocol.setProtocolName("GameBoard2DServer");		
	}

	/**
	 * Update the status bar with a new string
	 */
	public void updateStatus(String status)
	{
		this.statusTextField.setText(status);
	}	
}





